package pl.smath.regex;

import junit.framework.TestCase;
import pl.smath.expression.model.Term;
import pl.smath.expression.parser.ExpressionParser;
import pl.smath.expression.parser.ExpressionParserException;
import pl.smath.regex.exceptions.NoMatchFound;

public class TermMatcherTestCase extends TestCase {

	 /** 
     * 
     * Main testing class. Tests match between expression and term.
     * 
     * testFunction - {"expression", "matching term"}
     * testInvalid -  {"expression", "not matching term"}
     *  
     */
	
	private boolean DEBUG =  false; //true; //

    private static final String[][] TEST_DATA_NUMBERS = {
    	{"Number(a)", "7"},
    	{"-Number(b)", "-7"},
    	{"Number(c)", "17"},
    	{"Number(z)", "707"},
    	{"Number(c)", "(100)"},
    };
    
    private static final String[][] TEST_DATA_VARS = {
    	{"Variable(a)", "x"},
    	{"Variable(x)", "-y"},
    	{"Variable(g)", "(z)"},
    };
    
    private static final String[][] TEST_DATA_CONSTS = {
    	{"7", "7"},
    	{"-7", "-7"},
    	{"(7)", "7"},
    	{"7", "(7)"},
    	{"-(7)", "-7"},
    	{"-7", "-(7)"},
    	{"-(7)", "-(7)"},
    };
    
    private static final String[][] TEST_DATA_PLUS = {
    	{"7+5", "7+5"},
    	{"7+5", "7 + 5"},
    	{"999 + Number(a)", "999 + 5"},
    	{"999 + Variable(a)", "999 + h"},
    	{"999 + Variable(a)", "999 + zmienna"},
    	{"Variable(a) + 12", "zmienna + 12"},
    };
    
    private static final String[][] TEST_DATA_PLUS_MANY = {
    	{"7+5 + 4+3+2+1", "7+5+4+3+2+ 1"},
    	{"101 + 7+5 + Number(a) + Variable(asd)", "101 + 7 + 5 + 999 + niewiadoma"},
    	{"999 + Number(a) + 999 + Number(a)", "999 + 5 + 999 + 5"},
    	{"999 + Number(a) + 999 + Number(b)", "999 + 5 + 999 + 55"},
    	{"999 + Variable(a) + 999 + Variable(a)", "999 + h + 999 + h"},
    };
    
    private static final String[][] TEST_DATA_MINUS = {
    	{"7-5", "7-5"},
    	{"7+-5", "7 + -5"},
    	{"-Number(a) + 5", "-999 + 5"},
    	{"5^(-7)", "5^(-7)"},
    	{"5^-7", "5^-7"},
    	{"-Variable(x)", "-y"},
    	{"7-Variable(x)", "7-y"},
    	{"-7-Variable(x)", "-7-y"},
    	{"999 - Variable(a) + 999 - Variable(a)", "999 - h + 999 - h"},
    	{"999 - Variable(a) - 999 - Variable(a)", "999 - h - 999 - h"},
    };
    
    private static final String[][] TEST_DATA_EXP = {
    	{"7^5", "7^5"},
    	{"7^Variable(x)", "7^y"},
    	{"Variable(y)^Variable(x)", "x^y"},
    	{"Variable(a)^Variable(a)", "x^x"},
    	{"Variable(a)^-Variable(a)", "x^-x"},
    	{"(-Variable(a))^-Variable(a)", "(-x)^-x"},
    	{"-(Variable(a)^-Variable(a))", "-(x^-x)"},
    };
    
    private static final String[][] TEST_DATA_OPTIONAL = {
    	{"[Variable(x)*]7^5[+2-5]", "y*7^5"},
    	{"[Variable(x)*]7^5[+2-5]", "7^5"},
    	{"[Variable(x)*]7^5[+2-5]", "7^5+2-5"},
    	{"[Variable(x)*]7^5[+2-Number(v)]", "7^5+2-6"},
    	{"[9]9[9]", "999"},
    	{"[-]9", "-9"},
    	{"[-]9", "9"},
    	{"7 + [-]9", "7 - 9"},
    	{"7 + [-]9", "7 + 9"},
    };
    
    private static final String[][] TEST_DATA_ALTERNATIVE = {
    	{"7 [+|-] 9", "7 - 9"},
    	{"7 [+|-] 9", "7 + 9"},
    	{"Number(a) [*|/] Variable(t)", "7*x"},
    	{"Number(a) [*|/] Variable(t)", "7/y"},
    };
    
    private static final String[][] TEST_DATA_BASIC = {
		{"2+3+4", "(2+3)+4"},
		{"2+3+4", "2+3+4"},
		{"2+Number(a)+4", "2+(3)+4"},
		{"2+3+4", "(2)+3+4"},
		{"2+3+4", "(2+3+4)"},
		{"2+(3+4)", "2+(3+4)"},    		
		
		{"2*3*4", "(2*3)*4"},
		{"2*3*4", "2*3*4"},
		{"2*Number(a)*4", "2*(3)*4"},
		{"2*3*4", "(2)*3*4"},
		{"2*3*4", "(2*3*4)"},
		{"2*(3+4)", "2*(3+4)"},
		{"2*(3*4)", "2*(3*4)"},
		{"2*(3*4)+5", "2*(3*4)+5"},
		{"1+2*(3*4)+5", "1+2*(3*4)+5"},
		{"1*2*(3*4)+Number(a)", "1*2*(3*4)+5"},
		
		{"(2+Number(a))/(Variable(x)*5)", "(2 + 3)/(y*5)"},
    	{"Number(a) + Variable(x)", "3 + y"},
    	{"Number(a)*Variable(y)=2", "3y=2"},
    	{"Number(a)*Variable(y)[=2]", "5*x"},
    	{"Number(a)*Variable(y)[=2]", "5*x = 2"},
    	{"Number(a)[+|-]1=2", "1 + 1 = 2"},
		{"Number(a)[+|-]1=2", "5-1=2"},
		{"Variable(x) ^Number(a)", "z^3"},
		{"Number(a)^Number(b)", "5^10"},
		{"Number(a)^Variable(x) + Number(b)", "2^x + 3"},
		{"Number(a)^Variable(x) + 4", "2^x + 4"},
		{"(2+Number(a))/(Variable(x)*5)", "(2 + 3)/(y*5)"},
		{"(2+Number(a))/(5*Variable(x)) > Variable(t)", "(2 + 3)/(5*y) > z"},
    };
    
    private static final String[][] TEST_DATA_SUM = {
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n}", "2x^3+3x^2+4x+5"},
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n}", "x^7 + 2x^3+3x^2+4x+5"},
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n}", "(x^7)*4 + 2x^3+3x^2+4x+5"},
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n}", "x^7*4 + 2x^3+3x^2+4x+5"},
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n} + 2", "1+2*x^2+4x^4+6*x^6 + 2"},
    	{"Sum{n=0, n=infinity}{Number(a_n)*Variable(x)^n} + 2 * Variable(y)", "1+2*x^2+4x^4+6*x^6 + 2*z"},
    	{"Sum{n=0, n=3}{Number(a_n)*Variable(x)^n}", "2x^3+3x^2+4x+5"},
    	{"Sum{n=0, n=10}{Number(a_n)*Variable(x)^n}", "2*x^5"},
    	{"Sum{n=5, n=5}{Number(a_n)*Variable(x)^n}", "x^5"},
    };
    
    private static final String[][] TEST_DATA_INVALID = {
    	{"999 + Number(a) + 999 + Number(a)", "999 + 5 + 999 + 55"},
    	{"999 + Variable(a) + 999 + Variable(a)", "999 + h + 999 + gh"},
    	{"999 + Variable(a) + 999 + Variable(a)", "999 + h + 99 + h"},
    	{"999 + Variable(a) + 999 + Variable(a)", "999 + gh + 999 + h"},
    	{"Variable(a)", "7"},
    	{"Number(a)", "x"},
    	{"Sum{n=1, n=3}{Number(a_n)*Variable(x)^n}", "2x^3+3x^2+4x+5"},
    	{"Sum{n=1, n=3}{Number(a_n)*Variable(x)^n}", "x^5"},
    	{"-999", "999"},
    	{"999", "-999"},
    	{"Number(a)", "-999"},
    	{"-Number(a)", "999"},
    };
    
	
    private void testFunction(String testName, String[][] TEST_DATA) throws ExpressionParserException {
    	if (DEBUG)
    		System.err.println(testName + " STARTING");
    	
    	PatternBuilder pb = new PatternBuilder();
		Pattern p;
    	ExpressionParser parser = new ExpressionParser();
    	
    	int correct = 0;
        
        for(int i = 0; i < TEST_DATA.length; i++){
        		try {
        			p  = pb.compile(TEST_DATA[i][0]);
        			Term term = parser.parseText(TEST_DATA[i][1]);
    				Expression e = p.process(term); 
    				assertNotNull(e);
    				if (DEBUG)
    					System.err.println(testName + " TESTCASE " + i + " OK.");
    				correct++;
        		}
        		catch (NoMatchFound error) {
        			assertFalse("NoMatchFound Error" + error.getMessage(), false);
        			if (DEBUG)
    					System.err.println(testName + " TESTCASE " + i + " FAILED.");
        		}
        }
        
        System.err.println(testName + " SCORE: " + correct + "/" + TEST_DATA.length);
    }
    
    private void testInvalid(String testName, String[][] TEST_DATA) throws ExpressionParserException {
    	if (DEBUG)
    		System.err.println(testName + " STARTING");
    	
    	PatternBuilder pb = new PatternBuilder();
		Pattern p;
    	ExpressionParser parser = new ExpressionParser();
    	
    	int correct = 0;
        
        for(int i = 0; i < TEST_DATA.length; i++){
        		try {
        			p  = pb.compile(TEST_DATA[i][0]);
        			Term term = parser.parseText(TEST_DATA[i][1]);
    				Expression e = p.process(term); 
    				assertNotNull(e);
    				if (DEBUG)
    					System.err.println(testName + " TESTCASE " + i + " FAILED.");
        		}
        		catch (NoMatchFound error) {
        			assertFalse("NoMatchFound Error" + error.getMessage(), false);
        			if (DEBUG)
    					System.err.println(testName + " TESTCASE " + i + " OK.");
        			correct++;
        		}
        }
        
        System.err.println(testName + " SCORE: " + correct + "/" + TEST_DATA.length);
    }
	
       
    public void testNumbers()  throws ExpressionParserException {
    	testFunction("NUMBERS", TEST_DATA_NUMBERS);
    }
    
    public void testVars()  throws ExpressionParserException {
    	testFunction("VARS", TEST_DATA_VARS);
    }
        
    public void testConsts()  throws ExpressionParserException {
    	testFunction("CONSTS", TEST_DATA_CONSTS);
    }
       
    public void testPlus()  throws ExpressionParserException {
    	testFunction("PLUS", TEST_DATA_PLUS);
    }
        
    public void testPlusMany()  throws ExpressionParserException {
    	testFunction("PLUS_MANY", TEST_DATA_PLUS_MANY);
    }
        
    public void testMinus()  throws ExpressionParserException {
    	testFunction("MINUS", TEST_DATA_MINUS);
    }
        
    public void testExp()  throws ExpressionParserException {
    	testFunction("EXP", TEST_DATA_EXP);
    }
        
    public void testOptional()  throws ExpressionParserException {
    	testFunction("OPTIONAL", TEST_DATA_OPTIONAL);
    }
        
    public void testAlternative()  throws ExpressionParserException {
    	testFunction("ALTERNATIVE", TEST_DATA_ALTERNATIVE);
    }
       
    public void testBasic()  throws ExpressionParserException {
    	testFunction("BASIC", TEST_DATA_BASIC);
    }
	
    public void testSum()  throws ExpressionParserException {
    	testFunction("SUM", TEST_DATA_SUM);
    }
        
    public void testInvalid()  throws ExpressionParserException {
    	testInvalid("INVALID", TEST_DATA_INVALID);
    }
}
